#pragma once
#include "Socket.hpp"
#include <string>
#include <memory>
#include <jsoncpp/json/json.h>
#include <functional>

using namespace MySocket;

class Request
{
public:
    Request() {}
    Request(int x, int y, char oper) : _x(x), _y(y), _oper(oper)
    {
    }
    // 序列化
    std::string Serialize()
    {
        Json::Value root;
        Json::FastWriter writer;

        root["x"] = _x;
        root["y"] = _y;
        root["oper"] = _oper;

        std::string s = writer.write(root);
        return s;
    }
    // 反序列化
    bool DeSerialize(std::string &in)
    {
        Json::Value root;
        Json::Reader reader;

        bool ok = reader.parse(in, root);
        if (ok)
        {
            _x = root["x"].asInt();
            _y = root["y"].asInt();
            _oper = root["oper"].asInt();
        }
        return ok;
    }

    ~Request()
    {
    }

    const int X() { return _x; }
    const int Y() { return _y; }
    const char Oper() { return _oper; }

private:
    int _x;
    int _y;
    char _oper;
};

class Response
{
public:
    Response() {}
    Response(int result, int code)
        : _result(result), _code(code)
    {
    }
    std::string Serialize()
    {
        Json::Value root;
        Json::FastWriter writer;

        root["result"] = _result;
        root["code"] = _code;
        return writer.write(root);
    }
    bool DeSerialize(std::string &in)
    {
        Json::Value root;
        Json::Reader reader;

        bool ok = reader.parse(in, root);
        if (ok)
        {
            _result = root["result"].asInt();
            _code = root["code"].asInt();
        }
        return ok;
    }
    void ShowResult()
    {
        std::cout<<"计算结果为: "<<_result<<"["<<_code<<"]"<<std::endl;
    }
    ~Response()
    {
    }
    void SetRes(int res) { _result = res; }
    void SetCode(int code) { _code = code; }

private:
    int _result;
    int _code;
};

const std::string sep = "\r\n";
using func_t = std::function<Response (Request& req)>;

class Potorol
{
public:
    Potorol(){}
    Potorol(func_t func):_func(func)
    {}

    std::string Encode(const std::string &jsonstr)
    {
        std::string len = std::to_string(jsonstr.size());
        return len + sep + jsonstr + sep;
    }

    bool Decode(std::string& buffer,std::string *package)
    {
        ssize_t pos = buffer.find(sep);
        if(pos == std::string::npos)
            return false;
        
        std::string package_len_str = buffer.substr(0,pos);
        int package_len_int = std::stoi(package_len_str);

        int target_len = package_len_str.size() + package_len_int + 2*sep.size();
        if(buffer.size()<target_len)
            return false;
        
        *package = buffer.substr(pos+sep.size(),package_len_int);
        buffer.erase(0,target_len);
        return true;
    }

    void GetRequest(std::shared_ptr<Socket> &sock, InetAddr &client)
    {
        std::string buffer_queue;
        while(true)
        {
            int n = sock->Recv(&buffer_queue);
            if(n>0)
            {
                std::string json_package;
                while(Decode(buffer_queue,&json_package))
                {
                    // if(!ret)
                    //     continue;

                    Request req;
                    bool ok = req.DeSerialize(json_package);
                    if(!ok)
                        continue;

                    Response resp = _func(req);

                    std::string json_str = resp.Serialize();

                    std::string send_str = Encode(json_str);

                    sock->Send(send_str);
                }
            }
            else if(n==0)
            {
                LOG(Loglevel::INFO) << "client:" << client.GetString() <<" quit";
                break;
            }
            else
            {
                LOG(Loglevel::WARN)<<"client:"<<client.GetString()<<" recv error";
                break;
            }
        }
    }

    std::string BuildRequestString(int x,int y,char oper)
    {
        std::string json_str;
        Request req(x,y,oper);
        json_str = req.Serialize();

        return Encode(json_str);
    }

    bool GetResponse(std::shared_ptr<Socket> &client,std::string &resp_str,Response &resp)
    {
        while(true)
        {
            int n = client->Recv(&resp_str);
            if(n>0)
            {
                std::string json_package;

                // bool ret = Decode(resp_str,&json_package);
                // if(!ret)
                //     continue;
                while(Decode(resp_str,&json_package))
                {
                    resp.DeSerialize(json_package);
                    // resp.ShowResult();
                }
                return true;
            }
            else if(n==0)
            {
                std::cout << "Server: quit"<<std::endl;
                return false;
            }
            else
            {
                std::cerr <<"recv error"<<std::endl;
                return false;
            }
        }
        return true;
    }

    ~Potorol() {}

private:
    func_t _func;
    // Request _req;
    // Response _res;
};